package com.zhuchang.self_rpc.test.client;

import com.zhuchang.self_rpc.test.config.RpcConnectMannager;
import com.zhuchang.self_rpc.test.proxy.RpcAsyncProxy;
import com.zhuchang.self_rpc.test.proxy.RpcClientProxyImpl;

import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author RenPu
 * @Date 2021/8/18 10:17
 * @Version 1.0
 * @Description: 基于netty自定义RPC框架：客户端的编写
 **/
public class RpcClient {

    //连接地址
    private String serverAddress;

    //超时时间的设置
    private long timeout;

    //同步代理类缓存容器
    private final Map<Class<?>, Object> syncProxyConcurrentHashMap = new ConcurrentHashMap<Class<?>, Object>();

    //异步代理类缓存容器
    private final Map<Class<?>, Object> asyncProxyConcurrentHashMap = new ConcurrentHashMap<Class<?>, Object>();

    private RpcConnectMannager rpcConnectManager;

    private List<String> serverAddressList;


    /**
     * 初始化客户端的操作
     */
    public void initClient(String serverAddress, long timeout) {
        this.serverAddress = serverAddress;
        this.timeout = timeout;
        this.rpcConnectManager = new RpcConnectMannager();
        connect();
    }


    /**
     * initClient: 直接返回对应的代理对象，把RpcConnectManager透传到代理对象中
     *
     * @param <T>
     * @param serverAddress
     * @param timeout
     * @param interfaceClass
     * @return RpcProxyImpl
     */
    @SuppressWarnings("unchecked")
    public <T> T initClient(List<String> serverAddress, long timeout, Class<T> interfaceClass) {
        this.serverAddressList = serverAddress;
        this.timeout = timeout;
        this.rpcConnectManager = new RpcConnectMannager();
        this.rpcConnectManager.connect(this.serverAddressList);
        return (T) Proxy.newProxyInstance(
                interfaceClass.getClassLoader(),
                new Class<?>[]{interfaceClass},
                new RpcClientProxyImpl<>(rpcConnectManager, interfaceClass, timeout)
        );
    }

    public void updateConnectedServer(List<String> serverAddress) {
        this.serverAddressList = serverAddress;
        this.rpcConnectManager.updateConnectServer(serverAddress);
    }


    /**
     * 连接方法
     */
    public void connect() {
        RpcConnectMannager.getInstance().connect(serverAddress);
    }


    /**
     * 停止方法
     */
    public void stop() {
        RpcConnectMannager.getInstance().stop();
    }


    /**
     * 方式一：同步调用方法
     *
     * @param <T>
     * @return
     */
    public <T> T inovkeSync(Class<T> interfaceClass) {

        //1：为了节约资源将创建的代理类放入缓存容器
        if (syncProxyConcurrentHashMap.containsKey(interfaceClass)) {
            //先从缓存获取，有就直接返回，没有的话再进行创建
            return (T) syncProxyConcurrentHashMap.get(interfaceClass);
        } else {
            //2:获取代理类对象
            Object proxy = Proxy.newProxyInstance(interfaceClass.getClassLoader(),
                    new Class<?>[]{interfaceClass}, new RpcClientProxyImpl(rpcConnectManager, interfaceClass, timeout));
            return (T) proxy;
        }
    }


    /**
     * 方式二：异步调用方法
     *
     * @param <T>
     * @return
     */
    public <T> RpcAsyncProxy inovkeAsync(Class<T> interfaceClass) {

        //1：为了节约资源将创建的代理类放入缓存容器
        if (asyncProxyConcurrentHashMap.containsKey(interfaceClass)) {
            //先从缓存获取，有就直接返回，没有的话再进行创建
            return (RpcAsyncProxy) asyncProxyConcurrentHashMap.get(interfaceClass);
        } else {
            //2:获取代理类对象
            RpcAsyncProxy rpcAsyncProxy = new RpcClientProxyImpl(rpcConnectManager, interfaceClass, timeout);
            asyncProxyConcurrentHashMap.put(interfaceClass, rpcAsyncProxy);
            return rpcAsyncProxy;
        }
    }


}
